home *** CD-ROM | disk | FTP | other *** search
- /**
- GRAB Graph Layout and Browser System
-
- Copyright (c) 1986, 1988 Regents of the University of California
- Copyright (c) 1989, Tera Computer Company
- **/
-
- /**
- clip.c - routines to do edge clipping.
-
- The clipping routine is pretty naive, merely clipping against a box
- with the width and height of the node the edge is heading towards,
- even if the node happens to be, oh, say, an ellipse.
-
- Tricky points: circles don't necessarily have the same width as
- height, so the width is changed to match the height. The height could
- be changed to match the width, but when you do that, nodes with long
- names become really big. When you do it this way, long names tumble outside
- the node, but that doesn't look half bad.
-
- With multiple edges possible between two nodes, it is undesirable to
- have them all go to the same place. So, edges are shifted right or left
- a bit according to their ordinality. This works fine for large slopes,
- but gets worse and worse as the slope decreases. Horizontal lines
- must be handled by a special case. In any event, the layout routines
- prohibit horizontal edges, and tend to increase the slope of edges
- by putting adjacent nodes as close to vertical as possible. Edges
- added by the user might look bad, but they should be a small percentage.
- **/
-
- #include "attribute.h"
- #include "digraph.h"
- #include "screen.h"
- #include "clip.h"
-
- Clip(node, tonode, ord, from_x, from_y, to_x, to_y, screen)
- NODE *node, *tonode;
- int ord;
- double *from_x, *from_y;
- double *to_x, *to_y;
- SCREEN *screen;
- /**
- Clip the edge from node to tonode of ordinality ord and return
- the endpoints in to/from_x/y.
- **/
- {
- double shift;
-
- /* shift multiple edges from the same node */
- shift = (double) ORD_TO_SHIFT(ord);
-
- if (Y_position(node) == Y_position(tonode)) /* horizontal edge */
- {
- *from_x = (double) X_position(node);
- *from_y = (double) Y_position(node) + shift;
- *to_x = (double) X_position(tonode);
- *to_y = (double) Y_position(tonode) + shift;
- }
- else /* not horizontal */
- {
- *from_x = (double) X_position(node) + shift;
- *from_y = (double) Y_position(node);
- *to_x = (double) X_position(tonode) + shift;
- *to_y = (double) Y_position(tonode);
- }
-
- OneWayClip(tonode, from_x, from_y, to_x, to_y, screen);
- OneWayClip(node, to_x, to_y, from_x, from_y, screen);
- }
-
- OneWayClip(tonode, from_x, from_y, to_x, to_y, screen)
- NODE *tonode;
- double *from_x, *from_y;
- double *to_x, *to_y;
- SCREEN *screen;
- /**
- Clip the line from (from_x, from_y,) to (to_x, to_y) according
- to tonode
- **/
- {
- double xdist, ydist;
- double xright, xleft, ytop, ybottom;
-
- xright = (double) X_right(tonode);
- xleft = (double) X_left(tonode);
- ytop = (double) Y_top(tonode);
- ybottom = (double) Y_bottom(tonode);
-
- if (Shape(tonode) == CIRCLE)
- /* adjust right and left values to make it a circle */
- {
- double hh;
-
- hh = Half_height(tonode) / screen->zoom.yzoom * screen->zoom.xzoom;
- xright = (double) X_position(tonode) + hh;
- xleft = (double) X_position(tonode) - hh;
- }
- else if (Is_dummy(tonode))
- /**
- dummy nodes have width and height to insure they get enough
- space when layed out, but for clipping purposes they are just
- points
- **/
- {
- xright = *to_x;
- xleft = *to_x;
- }
-
- /* if y's are = need only find which side to draw to */
- if ((ydist = *from_y - *to_y) == 0)
- {
- if (*from_x > *to_x)
- {
- *to_x = xright;
- }
- else
- {
- *to_x = xleft;
- }
- }
- /* If y's <>, see if X's are = */
- else if ((xdist = *from_x - *to_x) == 0)
- {
- /* see what side to draw to */
- if (*from_y > *to_y)
- {
- *to_y = ytop;
- }
- else
- {
- *to_y = ybottom;
- }
- }
- else
- {
- /**
- otherwise if x's and y's are <>, aim for the top or bottom
- of the node
- **/
- if (*from_y > *to_y)
- {
- *to_y = ytop;
- }
- else
- {
- *to_y = ybottom;
- }
-
- *to_x = (xdist / ydist) * (*to_y - *from_y) + *from_x;
-
- /**
- if to_x is too small or too large, the line will hit the
- side of the node instead
- **/
- if ((*to_x < xleft) || (*to_x > xright))
- {
- if (*to_x < xleft)
- {
- *to_x = xleft;
- }
- else
- {
- *to_x = xright;
- }
-
- *to_y = (ydist / xdist) * (*to_x - *from_x) + *from_y;
- }
- }
- }
-